import pytz
from flask import request
from pyecharts.charts import Calendar, Pie, Timeline
import pyecharts.options as opts
from datetime import datetime, timezone, timedelta, date as datetime_date
from .models import Card, ReviewLog


def generate_review_calendar():
    """
    生成复习日历热力图接口
    """
    # 获取用户时区，默认为UTC
    user_timezone = request.args.get("timezone", "UTC")

    # 获取所有复习记录
    logs = ReviewLog.query.all()

    # 按日期统计复习次数
    date_counts = {}
    for log in logs:
        # 将UTC时间转换为用户本地时间
        utc_time = log.review_time.replace(tzinfo=timezone.utc)
        try:
            local_time = utc_time.astimezone(pytz.timezone(user_timezone))
            date = local_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1
        except:
            # 时区无效时使用UTC时间
            date = utc_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1

    # 如果无数据，使用最近一年的日期范围
    if not date_counts:
        end_date = datetime_date.today()
        begin_date = end_date - timedelta(days=365)
        data = [
            [str(begin_date + timedelta(days=i)), 0]
            for i in range((end_date - begin_date).days + 1)
        ]
    else:
        # 转换为pyecharts需要的格式
        data = [[date, count] for date, count in date_counts.items()]

    # 生成日历图
    calendar = (
        Calendar()
        .add(
            series_name="复习次数",
            yaxis_data=data,
            calendar_opts=opts.CalendarOpts(
                pos_top="120",
                pos_left="30",
                pos_right="30",
                range_=(
                    [min(date_counts.keys()), max(date_counts.keys())]
                    if date_counts
                    else None
                ),
                yearlabel_opts=opts.CalendarYearLabelOpts(is_show=False),
            ),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                pos_top="30", pos_left="center", title="复习日历"
            ),
            visualmap_opts=opts.VisualMapOpts(
                max_=max(date_counts.values()) if date_counts else 1,
                min_=0,
                orient="horizontal",
                is_piecewise=False,
            ),
            tooltip_opts=opts.TooltipOpts(formatter="{b}\n{c}次"),
        )
    )
    return calendar


def generate_create_calendar():
    """
    生成加卡日历热力图接口
    """
    # 获取用户时区，默认为UTC
    user_timezone = request.args.get("timezone", "UTC")

    # 获取所有卡片
    logs = Card.query.all()

    # 按日期统计创建次数
    date_counts = {}
    for log in logs:
        # 将UTC时间转换为用户本地时间
        utc_time = log.create_time.replace(tzinfo=timezone.utc)
        try:
            local_time = utc_time.astimezone(pytz.timezone(user_timezone))
            date = local_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1
        except:
            # 时区无效时使用UTC时间
            date = utc_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1

    # 如果无数据，使用最近一年的日期范围
    if not date_counts:
        end_date = datetime_date.today()
        begin_date = end_date - timedelta(days=365)
        data = [
            [str(begin_date + timedelta(days=i)), 0]
            for i in range((end_date - begin_date).days + 1)
        ]
    else:
        # 转换为pyecharts需要的格式
        data = [[date, count] for date, count in date_counts.items()]

    # 生成日历图
    calendar = (
        Calendar()
        .add(
            series_name="创建时间",
            yaxis_data=data,
            calendar_opts=opts.CalendarOpts(
                pos_top="120",
                pos_left="30",
                pos_right="30",
                range_=(
                    [min(date_counts.keys()), max(date_counts.keys())]
                    if date_counts
                    else None
                ),
                yearlabel_opts=opts.CalendarYearLabelOpts(is_show=False),
            ),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                pos_top="30", pos_left="center", title="加卡日历"
            ),
            visualmap_opts=opts.VisualMapOpts(
                max_=max(date_counts.values()) if date_counts else 1,
                min_=0,
                orient="horizontal",
                is_piecewise=False,
            ),
        )
    )
    return calendar


def generate_due_calendar():
    """
    生成复习进度日历图接口
    """
    # 获取用户时区，默认为UTC
    user_timezone = request.args.get("timezone", "UTC")

    # 获取所有卡片
    cards = Card.query.all()

    # 按日期统计卡片数量
    date_counts = {}
    for card in cards:
        # 将UTC时间转换为用户本地时间
        utc_time = card.due.replace(tzinfo=timezone.utc)
        try:
            local_time = utc_time.astimezone(pytz.timezone(user_timezone))
            date = local_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1
        except:
            # 时区无效时使用UTC时间
            date = utc_time.date().isoformat()
            date_counts[date] = date_counts.get(date, 0) + 1

    # 如果无数据，使用最近一年的日期范围
    if not date_counts:
        end_date = datetime_date.today()
        begin_date = end_date - timedelta(days=365)
        data = [
            [str(begin_date + timedelta(days=i)), 0]
            for i in range((end_date - begin_date).days + 1)
        ]
    else:
        # 转换为pyecharts需要的格式
        data = [[date, count] for date, count in date_counts.items()]

    # 生成日历图
    calendar = (
        Calendar()
        .add(
            series_name="卡片数量",
            yaxis_data=data,
            calendar_opts=opts.CalendarOpts(
                pos_top="120",
                pos_left="30",
                pos_right="30",
                range_=(
                    [min(date_counts.keys()), max(date_counts.keys())]
                    if date_counts
                    else None
                ),
                yearlabel_opts=opts.CalendarYearLabelOpts(is_show=False),
            ),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                pos_top="30", pos_left="center", title="复习进度"
            ),
            visualmap_opts=opts.VisualMapOpts(
                max_=max(date_counts.values()) if date_counts else 1,
                min_=0,
                orient="horizontal",
                is_piecewise=False,
            ),
            tooltip_opts=opts.TooltipOpts(formatter="{b}\n{c}张"),
        )
    )
    return calendar


def generate_rating_pie():
    """
    生成反馈饼图接口
    """
    # 获取所有反馈记录
    ratings = ReviewLog.query.filter(ReviewLog.rating != None).all()
    # 统计反馈
    rating_counts = {}
    for rating in ratings:
        rating_counts[rating.rating] = rating_counts.get(rating.rating, 0) + 1
    # 转换为pyecharts需要的格式
    data = [[rating, count] for rating, count in rating_counts.items()]
    pie = (
        Pie()
        .add(
            series_name="反馈",
            data_pair=data,
            radius=["40%", "75%"],
            center=["50%", "50%"],
            label_opts=opts.LabelOpts(formatter="{b}: {c} ({d}%)"),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                pos_top="30", pos_left="center", title="反馈统计图"
            ),
            tooltip_opts=opts.TooltipOpts(formatter="{a} <br/>{b}: {c} ({d}%)"),
        )
    )
    return pie


def generate_grade_subject_pie():
    """
    生成年级学科饼图接口
    """
    # 获取所有卡片
    cards = Card.query.all()
    tab = Timeline()
    for subject in set(map(lambda x: x.subject, cards)):
        pie = Pie()
        # 统计每个学科的年级数量
        grade_counts = {}
        for card in filter(lambda x: x.subject == subject, cards):
            grade_counts[card.grade] = grade_counts.get(card.grade, 0) + 1
        pie = pie.add(
            series_name=subject, data_pair=[[k, v] for k, v in grade_counts.items()]
        )
        tab.add(pie, subject)
    return tab


def register_plot_routes(app):
    @app.route("/api/plot", methods=["GET"])
    def plot():
        return [
            generate_create_calendar().dump_options_with_quotes(),
            generate_review_calendar().dump_options_with_quotes(),
            generate_due_calendar().dump_options_with_quotes(),
            generate_rating_pie().dump_options_with_quotes(),
            generate_grade_subject_pie().dump_options_with_quotes(),
        ]